/*
 * BtreeNode.cpp
 *
 *  Created on: Oct 26, 2011
 *      Author: hxu
 */

#include "BtreeNode.h"
#include<cstdlib>
#include<string>
#include<limits>
#include<cmath>
#include<sstream>

using namespace std;

extern double WIRER, WIREC;

namespace Cxuh {

void BtreeNode::initBtreeNode() {
	// initialization used for all constructors
	parent = NULL;
	lchild = NULL;
	rchild = NULL;
	name = "";
	dmax = numeric_limits<double>::min();
	dmin = numeric_limits<double>::max();
	A1 = 0.38;
	A2 = 0.693;
}

BtreeNode::BtreeNode(int id1, char nodetype) :
		type(nodetype), x(0), y(0), z(0), z2(0), C(0), R(0) {
	// Auto-generated constructor stub
	initBtreeNode();
	this->id = id1;
}

BtreeNode::BtreeNode(int id1, char nodetype, int x1, int y1, int z1) :
		type(nodetype), x(x1), y(y1), z(z1), z2(z1), C(0), R(0) {
	// Auto-generated constructor stub
	if (nodetype == 't')
		throw(" Error: initialize a tsv node without z2!");

	initBtreeNode();
	this->id = id1;
}

BtreeNode::BtreeNode(int id1, char nodetype, int x1, int y1, int z1, int z12) :
		type(nodetype), x(x1), y(y1), z(z1), z2(z12), C(0), R(0) {
	// Auto-generated constructor stub
	if (nodetype != 't')
		throw(" Error: initialize a non-tsv node with z2!");

	initBtreeNode();
	this->id = id1;
}

BtreeNode::~BtreeNode() {
	// Auto-generated destructor stub
}

int operator -(const BtreeNode& n1, const BtreeNode& n2) {
	// subtraction of coordinates, Manhattan distance
	int d, d1, d2;
	d1 = n1.getX() - n2.getX();
	d2 = n1.getY() - n2.getY();

	d = abs(d1) + abs(d2);

	return d;
}

std::ostream& operator<<(std::ostream& out, BtreeNode& obj) {

	string ntype;
	BtreeNode* par = obj.getParent();

	switch (obj.getType()) {
	case 'm':
		ntype = "Merge Point : ";
		break;
	case 's':
		ntype = "Sink : ";
		break;
	case 't':
		ntype = "TSV : ";
		break;
	case 'b':
		ntype = "BUF : ";
		break;
	default:
		ntype = "Other : ";
		break;
	}

	// print previous net
	if (par) {
		string pname = par->name;
		string name = obj.name;
		string net_name = pname + "_" + name;

		out << "Net : " << net_name << endl;
		out << "\tCoordinate : " << par->x << " " << par->y << " " << obj.x
				<< " " << obj.y << " " << obj.z << endl;
	}

	// print node
	out << ntype << obj.getID() << endl;
	out << "\tCoordinate : " << obj.getX() << " " << obj.getY() << " "
			<< obj.getZ();
	if (obj.getType() == 't')
		out << " " << obj.getZ2(); // 2nd tier connected to TSV
	out << std::endl;
	out << "\tCapacitive Load : " << obj.getC() << std::endl;

	return out;
}

void BtreeNode::calc_path_delay() {
	// calculate the min and max path delay
	double dlmin = numeric_limits<double>::max(), dlmax =
			numeric_limits<double>::min();
	double drmin = numeric_limits<double>::max(), drmax =
			numeric_limits<double>::min();
	double cl = 0, cr = 0;
	double l = 0, d = 0, d0 = 0;

	if (type == 's') {
		//leaf
		dmin = 0;
		dmax = 0;
	} else {
		if (lchild) {
			cl = lchild->get_in_cload();
			l = *this - *lchild;
			d = A1 * WIRER * WIREC * pow(l, 2) + A2 * WIRER * cl * l;
			dlmin = lchild->dmin + d;
			dlmax = lchild->dmax + d;
		}

		if (rchild) {
			cr = rchild->get_in_cload();
			l = *this - *rchild;
			d = A1 * WIRER * WIREC * pow(l, 2) + A2 * WIRER * cr * l;
			drmin = rchild->dmin + d;
			drmax = rchild->dmax + d;
		}

		d0 = getD() + A2 * getR() * (cl + cr); // intrinsic delay

		dmax = max(drmax, dlmax) + d0;
		dmin = min(drmin, dlmin) + d0;
	}
}

double BtreeNode::get_in_cload() const {
	// get the c load seen at the input of this node
	double inload = 0;
	int l1 = 0, l2 = 0; // distance between nd and its left and right children
	double c1, c2; // cap of lchild and rchild

	if (this->type == 's' || this->type == 'b')
		inload = this->getC();
	else {
		// TSV or merge point
		if (this->lchild) {
			l1 = *this - *(this->lchild);
			c1 = lchild->get_in_cload();
		} else {
			l1 = 0;
			c1 = 0;
		}
		if (this->rchild) {
			l2 = *this - *(this->rchild);
			c2 = rchild->get_in_cload();
		} else {
			l2 = 0;
			c2 = 0;
		}

		inload = this->getC() + (l1 + l2) * WIREC + c1 + c2;
	}

	return inload;
}

void BtreeNode::setLchild(BtreeNode * lchd) {
	lchild = lchd;
	if (lchd)
		lchd->parent = this;
}
void BtreeNode::setRchild(BtreeNode * rchd) {
	rchild = rchd;
	if (rchd)
		rchd->parent = this;
}

void BtreeNode::setChild(BtreeNode * chd) {
	if (!lchild)
		setLchild(chd);
	else if (!rchild)
		setRchild(chd);
	else
		throw(" Error: insert a child to a full node!");
}


void BtreeNode::setID(int i){
	id = i;
	stringstream ss;
	ss << type << id;
	ss >> name;
}

}
